package com.jahe.learn.netty4;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * @author: jahe.lai
 * @create: 2020-01-10 10:13
 */
public class ThreadPool {

    private static Logger logger = LoggerFactory.getLogger(ThreadPool.class);

    public static final int CORES = Runtime.getRuntime().availableProcessors();

    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return ++threadInitNumber;
    }
    private static int scheduleInitNumber;
    private static synchronized int nextScheduleNum() {
        return ++scheduleInitNumber;
    }

    /**
     * 线程池的核心线程数是CPU的核心的数目
     * 最大线程数是核心线程数的 2 倍。
     * 也就是 Worker线程的数目也是CPU的核心的数目，最大空闲时间是60秒(官方建议)。
     */
    private final static ThreadPoolExecutor threadPoolExecutor;

    private final static ScheduledExecutorService scheduleThread;

    static {
        threadPoolExecutor= new ThreadPoolExecutor(2,
                CORES * 2,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(),
                new ThreadFactory() {

                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "jahelai-worker-"+nextThreadNum());
                    }
                });

        scheduleThread = Executors.newScheduledThreadPool (2,
                        new ThreadFactory() {

                            @Override
                            public Thread newThread(Runnable r) {
                                return new Thread(r, "jahelai-schedule-"+nextScheduleNum());
                            }
                        });

        moniter();
    }





    static void moniter() {
        schedule(new Runnable() {
            @Override
            public void run() {
                /**
                 * 已安排线程池执行任务的大致数量 （有可能未执行完成）
                 */
                long taskCount = threadPoolExecutor.getTaskCount();
                /**
                 * 线程池在运行过程中已完成的大致任务数量
                 */
                long completedTaskCount = threadPoolExecutor.getCompletedTaskCount();
                /**
                 * 曾经创建过的最大线程数
                 */
                long largestPoolSize = threadPoolExecutor.getLargestPoolSize();
                /**
                 * 线程池里的线程数量
                 */
                long poolSize = threadPoolExecutor.getPoolSize();
                /**
                 * 线程池里正在执行任务的线程数量
                 */
                long activeCount = threadPoolExecutor.getActiveCount();

                logger.warn("taskCount:{}, completedTaskCount:{}, largestPoolSize:{}, poolSize:{}, activeCount:{}",
                        taskCount, completedTaskCount, largestPoolSize, poolSize, activeCount);
            }
        }, 300, 300);
    }


    public static void submit(Runnable task) {
        submit(task, null);
    }
    /**
     * 线程池执行任务。
     * @param task 任务
     * @param result 异步返回的结果
     * @return 异常时返回 null
     */
    public static <T> Future<T> submit(Runnable task, T result) {
        try {
            if (null == result) {
                threadPoolExecutor.submit(task);
            } else {
                Future<T> future = threadPoolExecutor.submit(task, result);
                return future;
            }
        } catch (Exception e) {
            logger.error("ThreadPool - run error ", e);
        }
        return null;
    }





    /**
     * 定时任务 （scheduleThread 只有一个线程。）
     * @param r 任务，建议逻辑代码用上面的线程池执行。因为 scheduleThread 只有一个线程。
     * @param initialDelaySecond 间隔秒数后执行任务
     * @param delaySecond 间隔秒数
     */
    public static void schedule(Runnable r, long initialDelaySecond,
                                long delaySecond) {
        schedule(r, initialDelaySecond, delaySecond, TimeUnit.SECONDS);
    }

    /**
     * 定时任务 （scheduleThread 只有一个线程。）
     * @param r 任务，建议逻辑代码用上面的线程池执行。因为 scheduleThread 只有一个线程。
     * @param initialDelay 前置间隔时间 （过了指定的时间，才会执行 Runnable 任务。）
     * @param delay 间隔时间 秒数
     * @param unit 时间单位
     */
    public static void schedule(Runnable r, long initialDelay,
                                long delay,
                                TimeUnit unit) {
        try {
            scheduleThread.scheduleWithFixedDelay(r, initialDelay, delay, unit);
        } catch (Exception e) {
            logger.error("scheduleThread - run error ", e);
        }
    }

    public static void shutdown() {
//        logger.warn("shutdown-threadpool ");
//        threadPoolExecutor.shutdown();
//        scheduleThread.shutdown();
//        logger.warn("shutdown-threadpool 【ok】 ");
    }
}
